home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1999 April / macformat-075.iso / Shareware Plus / Applications / Alpha / Tcl / Packages / elecExpansions.tcl < prev    next >
Encoding:
Text File  |  1999-01-31  |  23.5 KB  |  829 lines  |  [TEXT/ALFA]

  1. # Note from Vince: bug reports for this file should go to Tom Fetherston (install)
  2. # (and probably to me too, since I have made some changes)
  3.  
  4. ##===========================================================================
  5. # elecExpansions, formerly acronymExpansions, formerly 'Word-Combinations Completion'
  6.  
  7. # AUTHOR
  8. #    
  9. #    Thomas R. Fetherston
  10. #    Internet: ranch1@earthlink.net
  11. #    USnail:   94 Lipp Ave, Pittsburgh, PA 15229-2001
  12. #
  13. ################################################################################
  14. # HISTORY
  15. #                  
  16. # modified                 who rev reason
  17. # ----------------------   --- --- ------
  18. # 12/2/97                   trf 1.8 made changes to fix TeX expansions
  19. # 05/22/1997               trf 1.7 Removed uses of 'oneSpace', this messed up stop
  20. #                                    locations. 
  21. # 05/14/1997               VD  1.6 Changed proc names to reflect new naming scheme
  22. # 12/30/1996               trf 1.5 Modified so that this could be integrated with 
  23. #                                   Vince Darley's Completion package.
  24. # 07/14/1996 {01:21:20 PM} trf 1.4 Changed previous hit to a list of previous hits
  25. #                                   so hits would be offered only once.
  26. # 07/14/1996 {12:04:37 PM} trf 1.3 work around for regexp to include a close bracket
  27. # 07/12/1996 {12:53:38 AM} trf 1.2 Allow hint to be suffixed with certain puncuation
  28. #                                    marks and still be expanded. Added hint check.
  29. # 07/11/1996 {10:29:51 PM} trf 1.1 Allow expansion of hint prefixed with non-
  30. #                                   alphabetic character(s).
  31. #                                    Ensure Hit used is followed with only one
  32. #                                    space.
  33. # 07/05/1996 {10:28:20 PM} trf 1.0 Original
  34. ################################################################################
  35.  
  36. # Based on wordCompetion.tcl
  37. # Originally composed by Mark Nagata (nagata@kurims.kyoto-u.ac.jp) 
  38. # for Alpha 5.76, 4/22/94.
  39. # Modified by Tim van der Leeuw (tnleeuw@cs.vu.nl), 9/14/94.
  40. # Modified by Tom Fetherston
  41. # All the global variables needed to store state information between calls
  42. # (start with __Gcw_)
  43. #
  44. # This provides a different kind of word completion than the distribution provides, 
  45. # (wordCompletion.tcl).  When you find yourself typing a lot of variable and function 
  46. # names over and over, and these names are word-combinations where the name is formed by 
  47. # either capitalizing each word or separating them with an underscore, just type the 
  48. # initial letter of each word and invoke acronymExpansion instead.  
  49.  
  50. # The idea    of this    modification is    to allow you to    type a string consisting of    the    
  51. # initial letters of the words that    have been joined to make up 
  52. # a variable, function, or    procedure name.    This is    often shorter and more natural than    
  53. # typing a few letter and using wordCompletion. As I developed this routine I found that 
  54. # a regexp for more than three letters caused search to choke so only those letters of a
  55. # "hint" are significant. A three letter pattern is used for the search.  After a possible
  56. # hit is located, it is turned into an acronym and checked against the "hint"
  57. ##
  58. # to do list
  59. # ----------
  60. # change __Gcw_prevHint to a list of previous hits so we only get new hits
  61.  
  62. # monitor the character(s) to the right of the cursor point so the automatic, "oneSapce"
  63. # can be suppressed, e.g. if a comma, close "bracket", or return immediately follows,
  64. # let the inserted text abut it without a space
  65. # cause a hint that ends in an '[' to search for a hit that is
  66. # a parameterized routine. (what is a routine depends on the mode),
  67. # and invoke a "replacement that includes a template for the proper number of arguments
  68.  
  69. # let numerals play a role in finding a "Hit"
  70.  
  71. # let an invocation include a file or list to be searched instead of the current window.
  72. ##
  73. # The string you are going to use expansion on is    entered    in lowercase. The words in    
  74. # the target you are trying to hit have to start with a capital    
  75. # (except the first word), or, be separated    by an underscore.
  76.  
  77. # The hint can be embedded between non-alphabetic characters and certain punctuation marks
  78. # ( '[', '(', '{', ',', ';', ':', ''', '"', ']', ')', '}' ). The expanded hint remains
  79. # so embedded, and the cursor appears one space beyond the trailing punctuation.
  80.  
  81. # e.g. if sin($gl) was expanded, we would get sin($__Gcw_len) (in this file).
  82. # similarly, mouse($gph, would expand to 'mouse($__Gcw_prevHint, ', done twice, we would get
  83. # 'mouse($__Gcw_prevHit, '.
  84. ##,
  85. # The following binding is just a suggestion. It is the one that I like best, I have this
  86. # in my pref.tcl file
  87. # ascii 0x20 <c> bind::Expansion
  88. # i.e. command-<space>
  89.  
  90. #================================================================================
  91.  
  92. alpha::extension elecExpansions 9.0b3 {
  93.     alpha::package require elecBindings 9.0b1
  94.     lunion flagPrefs(Electrics) listPickIfMultExpds
  95.     # similarly for expansions
  96.     newPref flag listPickIfMultExpds 0
  97. } maintainer {
  98.     "Tom Fetherston" "" ""
  99. } uninstall this-file help {file "ElecCompletions Help"}
  100.  
  101. set __Gcw_prevHintPos -1
  102. set __Gcw_prevHint {}
  103. set __Gcw_prevsrcListName {}
  104.  
  105. ensureset __Gcw_already_expanding error
  106. ensureset __Gcw_pos_expanding -1 
  107.  
  108. ## 
  109.  # -------------------------------------------------------------------------
  110.  #     
  111.  #    "bind::Expansion"    --
  112.  #    
  113.  #     If    we're already completing, jump to that procedure, else go through
  114.  #     a mode-dependent list of expansion procedures    given by the array
  115.  #     'completions',    these return either    '1'    to indicate    termination, or
  116.  #     '0' to    say    either that    they failed    or that    they succeeded and that
  117.  #     further expansion    procedures may be applied.
  118.  # -------------------------------------------------------------------------
  119.  ##
  120. proc bind::Expansion {} {
  121.     if {![completion::tabDeleteSelection]} return
  122.     
  123.     global __Gcw_already_expanding
  124.     if {[elec::notAlreadyExpanding]} {
  125.     set __Gcw_already_expanding error
  126.     if {[expansion::user]} return
  127.     set m [modeALike]
  128.     global expanders
  129.     set curPos [getPos]
  130.     if {![catch {set expandersList $expanders($m)}]} {
  131.         foreach e $expandersList {
  132.         if {[completion $m $e]} return
  133.         }
  134.     }
  135.     #if none of the expanders succeeded, (or, don't exist) try
  136.     if {[pos::compare [getPos] == $curPos]} {
  137.         expansion::acronym
  138.     }
  139.     }
  140. }
  141.  
  142. ## 
  143.  # -------------------------------------------------------------------------
  144.  #     
  145.  #    "elec::notAlreadyExpanding" --
  146.  #    
  147.  #     Call this to check    if we should divert    directly to    a previously
  148.  #     registered    expansion procedure instead of    starting from scratch.
  149.  # -------------------------------------------------------------------------
  150.  ##
  151. proc elec::notAlreadyExpanding {} {
  152.     global __Gcw_already_expanding __Gcw_pos_expanding
  153.     # do the old expansion if possible
  154.     if {[pos::compare $__Gcw_pos_expanding == [getPos]]} {
  155.     return [catch {elec::completion [modeALike] $__Gcw_already_expanding}]
  156.     } else {
  157.     return 1
  158.     }    
  159. }
  160.  
  161. ## 
  162.  # -------------------------------------------------------------------------
  163.  #     
  164.  #    "elec::alreadyExpanding"    --
  165.  #    
  166.  #     If    a expansion routine has been called once, and would like to
  167.  #     be    called again (to cycle through a number    of possibilities), then
  168.  #     it    should register    itself with    this procedure.
  169.  # -------------------------------------------------------------------------
  170.  ##
  171. proc elec::alreadyExpanding { proc } {
  172.     global __Gcw_already_expanding __Gcw_pos_expanding
  173.     # store the given expansion
  174.     set __Gcw_already_expanding $proc
  175.     set __Gcw_pos_expanding [getPos]
  176. }
  177.  
  178.  
  179. ## 
  180.  # These declare, in order,    the    names of the expander
  181.  # procedures for each mode.  The actual procedure
  182.  # must    be named '${mode}Expansion::${listItem}', unless
  183.  # the item    is 'expansions::*' in which case that actual
  184.  # procedure is    called.
  185.  ##
  186. #===========================================================================
  187.  
  188. set expanders(TeX) {ExCmd}
  189. set expanders(Tcl) {}
  190. set expanders(C) {}
  191.  
  192. # just so we have one!
  193. set userExpansionw(date) {◊kill0◊[lindex [mtime [now]] 0]}
  194.  
  195. namespace eval expansion {}
  196.  
  197. proc expansion::user { {cmd ""} } {
  198.     if {![string length $cmd]} { set cmd [completion::lastWord] }
  199.     if {[containsSpace $cmd]} { return 0 }
  200.     
  201.     set curPos [getPos]
  202.     
  203.     elec::findCmd $cmd userExpansionw
  204.     #if the above call resulted in a detectable action, (i.e. the
  205.     # current positon has change), return 1
  206.     if {[pos::compare [getPos] == $curPos]} {
  207.     return 0
  208.     } else {
  209.     return 1
  210.     }
  211. }
  212.  
  213. #    -------------------
  214. proc expansion::acronym {} {
  215.     
  216.     global __Gcw_len
  217.     global __Gcw_prevHintPos
  218.     global __Gcw_prevHint
  219.     global __Gcw_endPrevRpl
  220.     global __Gcw_prevHits
  221.     global __Gcw_patt
  222.     global __Gcw_nextStart
  223.     global __Gcw_above_BELOW
  224.     
  225.     set To [getPos]
  226.     set lastChar [lookAt [pos::math $To - 1]]
  227.     set hintCapper [lookAt $To]
  228.     switch -- $hintCapper {
  229.     "\)" -
  230.     "\}" -
  231.     "\]" - 
  232.     " "  -
  233.     "\t" {
  234.         if {$lastChar != ","} {
  235.         set trailingWhite {} 
  236.         } else {
  237.         set trailingWhite " "
  238.         }     
  239.     }
  240.     "default" {
  241.         switch -- $lastChar {
  242.         "\(" -
  243.         "\{" -
  244.         "\{" - 
  245.         " "  -
  246.         "\t" {
  247.             set trailingWhite {} 
  248.         }
  249.         default {
  250.             set trailingWhite " "
  251.         }
  252.         }
  253.         
  254.     }
  255.     }
  256.     
  257.     backwardWord
  258.     set From [getPos]
  259.     
  260.     # adjust From to prune any non alphabetic prefix
  261.     set hint [getText $From $To]
  262.     
  263.     # The following variables may not come into existence in the regexp
  264.     #  below, so set up defaults.
  265.     set tail ""
  266.     set punc ""
  267.     #can not seem to include a close brack as below
  268.     #regexp {([a-zA-Z_]+)([\(\{\[,;:'"\}\)\]])*[     ]*$} $hint tail hint punc
  269.     
  270.     #work around on above
  271.     regexp {([a-zA-Z0-9_]+)(([\(\{\[,;:'"\}\)])*(\])*([\(\{\[,;:'"\}\)])*)[     ]*$} $hint tail hint punc
  272.     set From [pos::math $To - [string length $tail]]
  273.     
  274.     #   this is a 1stTry, but hint is illegal
  275.     if {[pos::compare $From != $__Gcw_prevHintPos]} {
  276.     if {[regexp {[0-9_]} $hint] > 0} {
  277.         alertnote "Ilegal hint, must have only letters in it."
  278.         select $From $To
  279.         set __Gcw_prevHintPos -1
  280.         return
  281.     } elseif {$From==$To} {
  282.         alertnote "Was not able to find any hint."
  283.         set __Gcw_prevHintPos -1
  284.         return
  285.     }
  286.     }
  287.     
  288.     
  289.     # adjust To, leaving trailing spaces or tabs
  290.     set To [expr $From + [string length [append junk $hint $punc]]]
  291.     
  292.     # if (Trying to complete a new hint)
  293.     if {[pos::compare $From != $__Gcw_prevHintPos]} {
  294.     set __Gcw_prevHint $hint
  295.     set __Gcw_prevHits {}
  296.     set __Gcw_len [string length $hint]
  297.     set __Gcw_patt  [pFI $hint]
  298.     set __Gcw_above_BELOW 0
  299.     
  300.     set start [pos::math $From - 1]    
  301.     set beg {}; set end {}
  302.     set foundAbove 0
  303.     elec::_searchAboveForHit start   beg end Hit foundAbove
  304.     
  305.     if {$foundAbove} {
  306.         lappend __Gcw_prevHits $Hit
  307.         
  308.         # put in the Hit, 
  309.         set replacement {}
  310.         append replacement $Hit $punc $trailingWhite 
  311.         replaceText $From $To $replacement
  312.         goto [pos::math $From + [string length $replacement]]
  313.         #         oneSpace
  314.         
  315.         
  316.         message "found above."
  317.         set __Gcw_prevHintPos $From
  318.         
  319.         set __Gcw_endPrevRpl [getPos]
  320.         elec::_adjustGlobals __Gcw_endPrevRpl  __Gcw_above_BELOW   __Gcw_nextStart
  321.         return
  322.     }
  323.     
  324.     set start $To    
  325.     set beg {}; set end {}
  326.     set __Gcw_above_BELOW 1
  327.     set foundBelow 0
  328.     elec::_searchBelowForHit start   beg end Hit foundBelow
  329.     
  330.     if {$foundBelow} {
  331.         lappend __Gcw_prevHits $Hit
  332.         
  333.         # put in the Hit, 
  334.         set replacement {}
  335.         append replacement $Hit $punc $trailingWhite 
  336.         replaceText $From $To $replacement
  337.         goto [pos::math $From + [string length $replacement]]
  338.         
  339.         message "found below."
  340.         set __Gcw_prevHintPos $From
  341.         
  342.         set __Gcw_endPrevRpl [getPos]
  343.         elec::_adjustGlobals __Gcw_endPrevRpl  __Gcw_above_BELOW   __Gcw_nextStart
  344.         return
  345.     }
  346.     
  347.     #No Hit for this hint exists
  348.     #     goto $To
  349.     #     backwardWordSelect
  350.     select $From $To
  351.     set __Gcw_prevHintPos -1
  352.     return
  353.     
  354.     # else: we are re-trying the previous hint
  355.     } else {  
  356.     while 1 {
  357.         #pre-set fndMsg, in case there is a valid Hit for this iteration
  358.         if {$__Gcw_above_BELOW} {
  359.         set fndMsg "found below."
  360.         } else {
  361.         set fndMsg "found above."
  362.         }
  363.         
  364.         set start $__Gcw_nextStart    
  365.         set beg {}; set end {}
  366.         set foundByContinuedSearch 0
  367.         elec::_continueSearchForHit start  beg end Hit foundByContinuedSearch
  368.         
  369.         if {$foundByContinuedSearch} {            
  370.         #if (this Hit is not the same as the last one)
  371.         if {[lsearch -exact $__Gcw_prevHits $Hit] == -1} {
  372.             
  373.             #add the hit to the list of previous hits
  374.             lappend $__Gcw_prevHits $Hit
  375.             
  376.             # put in the Hit, 
  377.             if {($punc == ",") && [info exists tail]} {
  378.             set trailingWhite " " 
  379.             } 
  380.             # put in the Hit, 
  381.             set replacement {}
  382.             append replacement $Hit $punc $trailingWhite 
  383.             replaceText $From $To $replacement
  384.             goto [pos::math $From + [string length $replacement]]
  385.             
  386.             message $fndMsg
  387.             set __Gcw_endPrevRpl [getPos]
  388.             elec::_adjustGlobals __Gcw_endPrevRpl  __Gcw_above_BELOW   __Gcw_nextStart
  389.             return
  390.             
  391.             #else: this Hit does not differ from the last
  392.         } else {
  393.             elec::_adjustGlobals __Gcw_endPrevRpl  __Gcw_above_BELOW   __Gcw_nextStart
  394.         }
  395.         
  396.         #else: another Hit was not found    
  397.         } else {
  398.         #if (no more Hits can exist, because we have searched all the text)
  399.         if {$__Gcw_above_BELOW} {
  400.             message "Not found."
  401.             #                 goto $To
  402.             #                 backwardWordSelect
  403.             select $__Gcw_prevHintPos $__Gcw_endPrevRpl
  404.             set __Gcw_prevHintPos -1
  405.             return
  406.             #else: we haven't tried BELOW
  407.         } else {
  408.             set __Gcw_above_BELOW 1
  409.             set __Gcw_nextStart $__Gcw_endPrevRpl
  410.         }
  411.         }
  412.         
  413.     }
  414.     }
  415. }
  416.  
  417. #    ---
  418. proc pFI wordStarters {
  419.     proc firstPost {char} {
  420.     return [format "(%s|%s)" [string toupper $char] $char ]
  421.     }
  422.     
  423.     proc fencePost {char} {
  424.     return [format {(%1$s|_%1$s|_%2$s)} [string toupper $char] $char ]
  425.     }
  426.     
  427.     set identifierLeader {(_|__)?}
  428.     set wordTail {[a-z0-9]*}
  429.     set identifierTail {[a-zA-Z0-9_]*}
  430.     
  431.     set idx_Last [expr {[string length $wordStarters]-1}]
  432.     if {$idx_Last>2} {set idx_Last 2}
  433.     
  434.     set searchPatt  $identifierLeader
  435.     append searchPatt [firstPost [string index $wordStarters 0]] 
  436.     append searchPatt $wordTail
  437.     
  438.     for {set i 1} {$i < $idx_Last} {incr i} {
  439.     append searchPatt [fencePost [string index $wordStarters $i]]
  440.     append searchPatt $wordTail
  441.     }
  442.     append searchPatt [fencePost [string index $wordStarters $i]]
  443.     append searchPatt $identifierTail
  444.     return $searchPatt
  445. }
  446.  
  447. #Note: in all the following scripts that start with uplevel…, the
  448. # agrguments are "fake", and serve only to show what variables
  449. # are used by these macro-like subroutines.  Their primary purpose
  450. # is to make the above code more readable.  Each is started with
  451. # an underscore to indicate that they are internal to another
  452. # routine, and should not be called by themselves.
  453.  
  454. #    ------------------  -in--  -out--------(bool)-
  455. proc elec::_searchAboveForHit {start  beg end Hit success} {
  456.     
  457.     uplevel {
  458.     set BegEnd {-1 -1}
  459.     set moreToSearch 1
  460.     while {$moreToSearch} {
  461.         set foundAbove [expr {![catch {search -s -f 0 -r 1 -i 0 -m 1 -- $__Gcw_patt $start} BegEnd]}]
  462.         set beg [lindex $BegEnd 0]
  463.         set end [lindex $BegEnd 1]
  464.         set Hit [getText $beg $end]
  465.         unset BegEnd
  466.         if {!$foundAbove} {break}
  467.         
  468.         set fullMatch [elec::acronymsAreEqual $hint $Hit]
  469.         if {$fullMatch} {
  470.         break
  471.         
  472.         } else {
  473.         set foundAbove 0
  474.         }
  475.         
  476.         if {[pos::compare $beg <= [minPos]]} {
  477.         set moreToSearch 0
  478.         } else {
  479.         set start [pos::math $beg-1]
  480.         }
  481.     }
  482.     }
  483. }
  484.  
  485. #    ------------------  -in--  -out--------(bool)-
  486. proc elec::_searchBelowForHit {start  beg end Hit success} {
  487.     
  488.     uplevel {
  489.     set BegEnd {-1 -1}
  490.     set moreToSearch 1
  491.     while {$moreToSearch} {
  492.         set foundBelow [expr {![catch {search -s -f 1 -r 1 -i 0 -m 1 -- \
  493.           $__Gcw_patt $start} BegEnd]}]
  494.         set beg [lindex $BegEnd 0]
  495.         set end [lindex $BegEnd 1]
  496.         set Hit [getText $beg $end]
  497.         unset BegEnd
  498.         if {!$foundBelow} {break}
  499.         
  500.         set fullMatch [elec::acronymsAreEqual $hint $Hit]
  501.         if {$fullMatch} {
  502.         break
  503.         
  504.         } else {
  505.         set foundBelow 0
  506.         }
  507.         
  508.         if {[pos::compare $end >= [maxPos]]} {
  509.         set moreToSearch 0
  510.         } else {
  511.         set start [expr $end]
  512.         }
  513.     }
  514.     }
  515. }
  516.  
  517. #    ---------------------  -in--  -out--------(bool)-
  518. proc elec::_continueSearchForHit {start  beg end Hit success} {
  519.     
  520.     uplevel {
  521.     set BegEnd {-1 -1}
  522.     set moreToSearch 1
  523.     while {$moreToSearch} {
  524.         set foundByContinuedSearch [expr {![catch {search -s -f $__Gcw_above_BELOW -r 1 -i 0 -m 1 -- \
  525.           $__Gcw_patt $__Gcw_nextStart} BegEnd]}]
  526.         set beg [lindex $BegEnd 0]
  527.         set end [lindex $BegEnd 1]
  528.         set Hit [getText $beg $end]
  529.         unset BegEnd
  530.         if {!$foundByContinuedSearch} {break}
  531.         
  532.         set fullMatch [elec::acronymsAreEqual $__Gcw_prevHint $Hit]
  533.         if {$fullMatch} {
  534.         break
  535.         } else {
  536.         set foundBelow 0
  537.         }
  538.         
  539.         if {[pos::compare $end >= [maxPos]]} {
  540.         set moreToSearch 0
  541.         } else {
  542.         elec::_adjustGlobals __Gcw_endPrevRpl  __Gcw_above_BELOW   __Gcw_nextStart
  543.         }
  544.     }
  545.     }
  546. }
  547.  
  548. #    --------------  -in-------------  -mod-------------   -out-----------
  549. proc elec::_adjustGlobals {__Gcw_endPrevRpl  __Gcw_above_BELOW   __Gcw_nextStart} {
  550.     
  551.     uplevel {
  552.     if {$__Gcw_above_BELOW} {
  553.         set __Gcw_nextStart $end
  554.     } else {
  555.         set __Gcw_nextStart [pos::math $beg - 1]
  556.         if {[pos::compare $__Gcw_nextStart <= [minPos]]} {
  557.         set __Gcw_above_BELOW 1
  558.         set __Gcw_nextStart $__Gcw_endPrevRpl
  559.         }
  560.     }
  561.     }
  562. }
  563.  
  564.  
  565.  
  566. #    ----------(bool)  -in- ---------------
  567. proc elec::acronymsAreEqual {hint wordCombination} {
  568.     
  569.     
  570.     set splitOnUndrS [split $wordCombination {_}]
  571.     set shoe {}
  572.     foreach part $splitOnUndrS {
  573.     if {$part == {}} continue
  574.     set part [split $part {}]
  575.     set part [lreplace $part 0 0 [string toupper [lindex $part 0]]]
  576.     set part [join $part {}]
  577.     append shoe $part
  578.     }
  579.     regsub -all \[a-z0-9\] $shoe {} shoe
  580.     return [expr {![string compare [string toupper $hint] $shoe]}]
  581. }
  582.  
  583.  
  584. ## 
  585.  # -------------------------------------------------------------------------
  586.  #     
  587.  #    "elec::acronymListExpansions" --
  588.  #    
  589.  #     Given a an acronym of the sub-words in a 'multi-word command' (the 'hint')
  590.  #   and the name of a    list to    search,    that list consisting of 
  591.  #   acronyms-command pairs on separate lines that have been placed in
  592.  #     alphabetical order    and    starting/ending    with a
  593.  #     return, this proc returns a list of all pairs that have the hint as
  594.  #   their first element or'0'    if there were none. 
  595.  #   
  596.  #     Based on Vince Darley's modeListCompletions
  597.  # -------------------------------------------------------------------------
  598.  ##
  599. proc elec::acronymListExpansions { hint dictName } {
  600.     global $dictName
  601.     
  602.     set reg {(\n}
  603.     append reg $hint { +[^\n]+)+}
  604.     if {[regexp $reg [set $dictName] pairs]} {
  605.     set odd 1
  606.     foreach m $pairs {
  607.         if {$odd % 2 != 0} {
  608.         incr odd
  609.         continue
  610.         } 
  611.         incr odd
  612.         append matches $m " "
  613.     }
  614.     return $matches
  615.     } else {
  616.     return 0
  617.     }
  618. }
  619.  
  620. proc elec::expandThis { cmd matches {isdbllist 0} {forcequery 0}} {
  621.     global possMatches returnedMatch listPickIfMultExpds
  622.     
  623.     set possMatches $matches
  624.     set mquery [set match [lindex $matches 0]]
  625.     if {$isdbllist} { set match [lindex [lindex $match 0] 0]}
  626.     if { [set cmdnum [llength $matches]] == 1 || $match == $cmd } {
  627.     # It's unique or already a command, so insert it 
  628.     backwardDeleteWord
  629.     elec::commandPrefix
  630.     insertText $match
  631.     return $match
  632.     } else {
  633.     set item [lindex $matches [incr cmdnum -1]]
  634.     if {$isdbllist} { set item [lindex [lindex $item 0] 0] }
  635.     
  636.     set num 1
  637.     set correspondingNum 1
  638.     set numberedChoices "\{"
  639.     set currChoiceSet ""
  640.     set setIdx 0
  641.     set multiSets 0
  642.     set pickNumOfStartIn(0) $correspondingNum
  643.     foreach m $matches {
  644.         append numberedList "\{$num $m\} "
  645.         #make up a list of choiceSets, where eadh choice set has < 79
  646.         # characters
  647.         if {[string length "$currChoiceSet$correspondingNum $m "] < 77} {
  648.         append numberedChoices "$correspondingNum $m "
  649.         append currChoiceSet   "$correspondingNum $m "
  650.         set setAndNum($num) [list $setIdx $correspondingNum]
  651.         } else {
  652.         incr setIdx
  653.         set correspondingNum 1
  654.         append numberedChoices "m…\} \{$correspondingNum $m "
  655.         set currChoiceSet      "$correspondingNum $m "
  656.         set setAndNum($num) [list $setIdx $correspondingNum]
  657.         set pickNumOfStartIn($setIdx) $num
  658.         set multiSets 1
  659.         }
  660.         incr correspondingNum
  661.         incr num
  662.     }
  663.     if {$multiSets} {
  664.         append numberedChoices "b…\}"
  665.     } else {
  666.         append numberedChoices "\}"
  667.     }
  668.     
  669.     
  670.     
  671.     if { $listPickIfMultExpds } {
  672.         beep
  673.         if {[catch { set choice [listpick -p "Pick an expansion" $numberedList]}]} {
  674.         message "Cancelled"
  675.         return 1
  676.         } else {
  677.         backwardDeleteWord
  678.         elec::commandPrefix
  679.         set choice [lindex $choice 1]
  680.         insertText $choice
  681.         return $choice
  682.         }
  683.         
  684.     } else {
  685.         set pickNum 1
  686.         set promptNum $pickNum
  687.         set currChoiceSet_idx 0
  688.         set c "\t"
  689.         backwardDeleteWord
  690.         elec::commandPrefix
  691.         insertText [lindex $matches 0]
  692.         
  693.         while {[set c] == "\t"} {
  694.         set currChoiceSet_idx [lindex $setAndNum($pickNum) 0]
  695.         set currChoiceSet     [lindex $numberedChoices $currChoiceSet_idx]
  696.         #look up what number in the currChoiceSet corresponds to the pickNum
  697.         set currNum [lindex $setAndNum($pickNum) 1]
  698.         regsub "$currNum " $currChoiceSet "=>" choices
  699.         global returnedMatch
  700.         set returnedMatch ""
  701.         
  702.         message $choices
  703.         set c [getChar]
  704.         set c [string tolower $c ]
  705.         scan $c "%c" decRep
  706.         if {$decRep == 27} {
  707.             set c "esc"
  708.         } 
  709.         switch -- $c {
  710.             "\t" {
  711.             incr pickNum
  712.             if {$pickNum > [llength $matches]} {
  713.                 set pickNum 1
  714.             } 
  715.             backwardDeleteWord
  716.             elec::commandPrefix
  717.             insertText [lindex $matches [expr {$pickNum -1}]]
  718.             #set things up so we cylce to the next choice
  719.             continue                      
  720.             }
  721.             " " -
  722.             "\\" -
  723.             "\r" {
  724.             #these keys indicate that we are satisfied with the current choice,
  725.             # just insert the key pressed
  726.             #                       alertnote "you pressed a return, \\, or space"
  727.             #                       alertnote "pickNum = $pickNum"
  728.             return [list [lindex $matches [expr {$pickNum -1}]] $c]
  729.             }
  730.             "m" {
  731.             #when there are more choices than can be diplayed on the statusline
  732.             # pressing 'm', will get the next set of choices
  733.             if {[string match "*m…" $currChoiceSet]} {
  734.                 set pickNum $pickNumOfStartIn([expr {$currChoiceSet_idx +1}])
  735.             }
  736.             if {[string match "*b…" $currChoiceSet]} {
  737.                 set pickNum 1
  738.             } 
  739.             backwardDeleteWord
  740.             elec::commandPrefix
  741.             insertText [lindex $matches [expr {$pickNum -1}]]
  742.             #set things up so we cylce to the next choice
  743.             set c "\t"
  744.             continue
  745.             }
  746.             "b" {
  747.             #when there are more choices than can be diplayed on the statusline
  748.             # pressing 'b', will get the first set of choices
  749.             set pickNum 1
  750.             set c "\t"
  751.             backwardDeleteWord
  752.             elec::commandPrefix
  753.             insertText [lindex $matches [expr {$pickNum -1}]]
  754.             #set things up so we cylce to the next choice
  755.             continue
  756.             }
  757.             "esc" {
  758.             #when you want to bypass this and get to acronymExpansion
  759.             backwardDeleteWord
  760.             insertText $cmd
  761.             return 0
  762.             }
  763.             "default" {
  764.             #see if c is, or can be converted to, a number in the range 1-9
  765.             set strPos [string first $c "asdfghjkl123456789"]
  766.             if {$strPos == -1} {
  767.                 beep
  768.                 return
  769.             }
  770.             set numberChoosen [expr {$strPos % 9}]
  771.             if {$numberChoosen > [llength $possMatches]} {
  772.                 beep
  773.                 return
  774.             } 
  775.             #alertnote "you choose number $numberChoosen"    
  776.             set returnedMatch [lindex $possMatches [expr {$pickNumOfStartIn($currChoiceSet_idx) + $numberChoosen -1}]]
  777.             
  778.             
  779.             }
  780.         }
  781.         #             catch {statusPrompt -f $choices statusLineChooser}
  782.         if {$returnedMatch != ""} {
  783.             backwardDeleteWord
  784.             elec::commandPrefix
  785.             insertText $returnedMatch
  786.             return $returnedMatch                
  787.         } 
  788.         
  789.         }
  790.         
  791.     }
  792.     
  793.     return ""
  794.     }
  795.     
  796.     
  797. }
  798.  
  799.  
  800.  
  801. proc elec::commandPrefix {} {
  802.     global mode
  803.     
  804.     switch -- $mode {
  805.     "TeX" {
  806.         set pos [getPos]
  807.         set bol [getText [lineStart $pos] $pos]
  808.         switch -glob $bol {
  809.         "*\\begin\{" -
  810.         "*\\end\{" - 
  811.         "*\\" {
  812.             return
  813.         }
  814.         "default" {
  815.             insertText "\\"
  816.         }
  817.         }
  818.     }
  819.     }
  820. }
  821.                     
  822.  
  823.  
  824.